/******************************************************************************

    SlkTree.cpp

******************************************************************************/

#include "SlkTree.h"

#define FALSE       0 
#define TRUE        1 
// #define PRINTF      printf 
#define PRINTF(a,b)

SlkTree :: node2_t *
SlkTree ::
make_node ( slk_size_t    token )
{
    register
    node2_t    *node;

    node = (node2_t *)  calloc ( 1, sizeof ( node2_t ) );
    if ( node == NULL ) {
        puts ( "make_node calloc failed\n" );
        exit (1);
    }
    node->token = token;
    if ( SlkIsTerminal ( token ) ) {
        // node->value = (int) Last_attribute;
    }

    return ( node );
}

// -----------------------------------------------------------------------
// public 
// -----------------------------------------------------------------------

void    
SlkTree ::
reduce ( slk_size_t production_number )
{
    register
    slk_size_t   *rhs;
    register
    node2_t      *prev = NULL;
    node2_t      *child = NULL;
    node2_t      *this_child = NULL;
    slk_size_t   *lhs;
    int           length,
                  rhs_length;

    if ( Display ) {
        puts ( SlkGetProductionName ( production_number ) );
    }
    lhs = SlkGetProductionArray ( production_number );
    rhs_length = *lhs - 1;
    ++lhs;
    rhs = lhs + 1;
    for ( length = rhs_length;  length > 0;  --length, ++rhs ) {
        if ( SlkIsAction ( *rhs ) ) {
            continue;                               // skip actions
        }
        prev = make_node ( *rhs );
        this_child = prev;
        for ( --length, ++rhs;  length > 0;  --length, ++rhs ) {
            if ( SlkIsAction ( *rhs ) ) {
                continue;                               // skip actions
            }
            prev->sibling = make_node ( *rhs );
            prev->sibling->left_sibling = prev;
            prev = prev->sibling;
        }
    }
    for (;  prev;  prev = prev->left_sibling ) {
        if ( SlkIsNonterminal ( prev->token ) ) {
            child = Parse_stack.pop ();
            if ( child ) {
                PRINTF ( "pop :   %s\n", SlkGetSymbolName ( child->token ) );
                prev->child = child;
                child->parent = prev;
            } else {
                PRINTF ( "pop :   %s\n", "NULL" );
            }
        }
    }
    if ( this_child ) {
        PRINTF ( "push:   %s\n", SlkGetSymbolName ( this_child->token ) );
    } else {
        PRINTF ( "push:   %s\n", "NULL" );
    }
    Parse_stack.push ( this_child );
    if ( production_number == 1 ) {
        Root = make_node ( *lhs );
        Root->child = this_child;
        this_child->parent = Root;
    }
}

SlkTree::node2_t*
SlkTree ::
make_LL_branch ( slk_size_t  production_number )
{
    register
    slk_size_t   *rhs;
    register
    node2_t      *prev = NULL;
    node2_t      *child = NULL;
    slk_size_t   *lhs;
    int           length,
                  rhs_length;

    lhs = SlkGetProductionArray ( production_number );
    rhs_length = *lhs - 1;
    ++lhs;
    rhs = lhs + 1;
    for ( length = rhs_length;  length > 0;  --length, ++rhs ) {
        if ( SlkIsAction ( *rhs ) ) {
            continue;                               // skip actions
        }
        prev = make_node ( *rhs );
        child = prev;
        for ( --length, ++rhs;  length > 0;  --length, ++rhs ) {
            if ( SlkIsAction ( *rhs ) ) {
                continue;                           // skip actions
            }
            prev->sibling = make_node ( *rhs );
            prev->sibling->left_sibling = prev;
            prev = prev->sibling;
        }
    }
    for (;  prev;  prev = prev->left_sibling ) {
        if ( SlkIsNonterminal ( prev->token ) ) {
            Parse_stack.push ( prev );                 // copy parsing pushes
        }
    }

    return  child;
}

void    
SlkTree ::
predict ( slk_size_t  production_number )
{
    register
    slk_size_t   *rhs;
    slk_size_t   *lhs;
    node2_t      *parent;
    node2_t      *child;

    if ( Display ) {
        puts ( SlkGetProductionName ( production_number ) );
    }
    lhs = SlkGetProductionArray ( production_number );
    ++lhs;
    if ( ! Root ) {                                    // first call
        Root = make_node ( *lhs );
        Parse_stack.push ( Root );
    }
    parent = Parse_stack.pop ();
    child = make_LL_branch ( production_number );
    if ( child  &&  parent ) {
        parent->child = child;
        child->parent = parent;
    }
}

void 
SlkTree ::
pre_order ( node2_t   *tree )
{
    register
    node2_t  *child,
            *sibling;

    if ( tree == NULL ) {
        return;
    }
    printf ( "%s\n", SlkGetSymbolName ( tree->token ) );

    child = tree->child; 

    if ( child != NULL ) {
        pre_order ( child );
    
        for ( sibling = child->sibling;  sibling;  sibling = sibling->sibling ) {
            pre_order ( sibling );
        }
    }
}

void 
SlkTree ::
show_tree ( void )
{
    pre_order ( Root );
}


void 
SlkTree ::
show_parse_derivation ( void )
{
    show_parse_derivation ( Root );
}


void 
SlkTree ::
show_parse_derivation ( node2_t   *tree )
{
    register
    node2_t  *child,
            *sibling;

    if ( tree == NULL ) {
        return;
    }
    printf ( "%s --> ", SlkGetSymbolName ( tree->token ) );

    child = tree->child; 

    if ( child != NULL ) {
        printf ( "%s ", SlkGetSymbolName ( child->token ) );
        for ( sibling = child->sibling;  sibling;  sibling = sibling->sibling ) {
            printf ( "%s ", SlkGetSymbolName ( sibling->token ) );
        }
        putchar ( '\n' );
    
        if ( SlkIsNonterminal ( child->token ) ) {
            show_parse_derivation ( child );
        } 

        for ( sibling = child->sibling;  sibling;  sibling = sibling->sibling ) {
            if ( SlkIsNonterminal ( sibling->token ) ) {
                show_parse_derivation ( sibling );
            }
        }
    } else { 
        putchar ( '\n' );
    }
}

SlkTree ::
SlkTree ( int display )
{              
    Root = NULL;
    Current = NULL;
    Display = display;
}

